#region File Header
//----------------------------------------------------------------
// Copyright (C) 2002 Stefan Kyntchev
// All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT 
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR 
// FITNESS FOR A PARTICULAR PURPOSE.
//----------------------------------------------------------------
#endregion File Header

namespace AirWeb.DirectoryMgr
{
	using System;
	using System.IO;
	using System.Collections;

	public delegate void IncludeFilter(FileSystemInfo i_di, ArrayList i_currentContent, ref bool i_include);

	//TODO Directory list must support security and filtering and other algorhims
    /// <summary>
    ///    Summary description for DirectoryLister.
    /// </summary>
    /// 
    public class DirectoryLister
	{
		ArrayList m_Files = new ArrayList();
		static int m_curr_depth;
		static int m_max_depth;
		int m_filter = 0;
		FileComparer m_comparer = null;
		public IncludeFilter m_Filters = null;

		public DirectoryLister()
		{}

		public ArrayList ListFiles(String i_Dir, int i_depth)
		{
			return List(i_Dir,i_depth,false);	
		}

		public ArrayList ListDirectories(String i_Dir, int i_depth)
		{
			return List(i_Dir,i_depth,true);	
		}

		public void AddFilter(IncludeFilter i_filter)
		{
			m_Filters += i_filter;
		}

	    protected ArrayList List(String i_Dir, int i_depth, bool i_directories )
	    {
			m_Files.Clear();

			m_curr_depth = 0;
			m_max_depth = i_depth;

			if(i_Dir == "")
				return m_Files;

	        DirectoryInfo dir = new DirectoryInfo(i_Dir);

			if(!dir.Exists)
				return m_Files;

			if(i_directories)
			{
				TraverseDirectories(dir,false);
			}
			else
			{
				TraverseFiles (dir);	
			}

			// Sort the elements using an external comparrer;
			if(m_comparer != null)
				m_Files.Sort(m_comparer);
	        
			return m_Files;
	    }

	    protected void TraverseFiles (DirectoryInfo dir)
	    {
			if(!dir.Exists)
			{
				return;
			}

			m_curr_depth++;

	        foreach (FileSystemInfo d in dir.GetFileSystemInfos ())
	        {
	            if (d is FileInfo)
	            {
	                FileInfo f = (FileInfo) d;

					if(ShouldDisplay((FileSystemInfo)f))
						m_Files.Add(f);
	            }
	            else //it must be a directory
	            {
					if(m_curr_depth <= m_max_depth)
					{
					  TraverseFiles ((DirectoryInfo) d);
					}
	            }
	        }
			
			m_curr_depth--;

	    }

		protected bool TraverseDirectories (DirectoryInfo dir, bool i_isTest)
	    {
			if(!dir.Exists)
			{
				return false;
			}

			m_curr_depth++;

	        foreach (FileSystemInfo d in dir.GetFileSystemInfos ())
	        {
	            if (d is FileInfo)
	            { }
	            else //it must be a directory
	            {
					DirectoryInfo dr = (DirectoryInfo) d;

					// filter out directories based on time
					if( ShouldDisplay((FileSystemInfo)dr) )
					{
						if(i_isTest == false)
							m_Files.Add(dr);
						else
							return true;
					}
					else
					{
						if( m_Filters != null )  // do deep filtering only if the filter exists
						{
							bool rv = TraverseDirectories(dr,true);
							if(i_isTest == true && rv == true)
								return rv;
							else if(rv == true)
							{
								m_Files.Add(dr);			
							}
						}
					}

					if((m_curr_depth <= m_max_depth) || i_isTest == true)
					{
					  TraverseDirectories (dr,i_isTest);
					}
	            }
	        }

			m_curr_depth--;
			return false;
		}

		protected bool ShouldDisplay(FileSystemInfo i_info)
		{
			bool should = true;
			if(m_Filters == null)
					return should;

			// Call all filtering agents in sequence. If some of them sets should to false dont' include
			m_Filters(i_info, m_Files, ref should);
			
			return should;
		}

		public int Filter1
		{
			set
			{
				m_filter = value;
			}
			get
			{
				return m_filter;
			}
		}

		public FileComparer Comparer
		{
			set
			{
				m_comparer = value;
			}
		}

	}
}
